/*
 *  liquidity/container-model.vala
 *
 *  Copyright (c) 2008 Patrick Walton <pcwalton@uchicago.edu>
 */

using GLib;
using Gee;
using Clutter;

namespace Liquidity {
    public class ContainerModel : ActorModel {
        public override Behaviour get_behavior_for_key_path(string key_path,
                Alpha alpha, Timeline timeline)
        {
            return null;    /* TODO */
        }

        protected ArrayList<ActorModel> _submodels;
        
        construct {
            _submodels = new ArrayList<ActorModel>();
            _supermodel = null;
        }

        private void _submodel_added(ActorModel model)
        {
            model._set_supermodel(this);

            /*
             *  As below, we don't add the actor here to the model's children.
             *  The reason is more subtle: we don't want the actor to be added
             *  until the animation begins. In the normal case of fade-in, this
             *  would result in a flash before the fade in occurs.
             */

            Transaction._add_update(new Update(model, "added"));
            stdout.printf("submodel added\n"); 
        }

        private void _submodel_removed(ActorModel model)
        {
            model._set_supermodel(null);

            /*
             *  We don't remove the actor from the presentation container
             *  because we will need to animate it away (usually with opacity
             *  fade out). The submodel will handle this in its
             *  get_behavior_for_key_path method.
             */

            Transaction._add_update(new Update(model, "removed"));
            stdout.printf("submodel removed\n");
        }

        public void _remove_submodel(ActorModel victim)
        {
            assert(_submodels.remove(victim));
            _submodel_removed(victim);

            victim._set_supermodel(null);
        }

        public void insert_submodel_at_index(ActorModel kid, int index)
        {
            assert(kid.supermodel != this);
            assert(index >= 0 && index <= ((Collection)_submodels).size);

            _submodels.insert(index, kid);
            kid._set_supermodel(this);
            _submodel_added(kid);
        }

        public void add_submodel(ActorModel kid)
        {
            insert_submodel_at_index(kid, ((Collection)_submodels).size);
        }

        public void insert_submodel_below(ActorModel kid, ActorModel referent)
        {
            insert_submodel_at_index(kid, _submodels.index_of(referent));
        }

        public void insert_submodel_above(ActorModel kid, ActorModel referent)
        {
            insert_submodel_at_index(kid, _submodels.index_of(referent) + 1);
        }

        public void replace_submodel_with(ActorModel old_m, ActorModel new_m)
        {
            int index = _submodels.index_of(old_m);
            assert(index > -1);

            old_m.remove_from_supermodel();
            insert_submodel_at_index(new_m, index);
        }

        public Gee.List<ActorModel># submodels {
            get {
                return new ReadOnlyList<ActorModel>(_submodels);
            }
            set {
                foreach (ActorModel model in value)
                    if (!_submodels.contains(model))
                        _submodel_added(model);
                foreach (ActorModel model in _submodels)
                    if (!value.contains(model))
                        _submodel_removed(model);

                _submodels.clear();
                foreach (ActorModel model in value)
                    _submodels.add(model);
            }
        }

        protected override void _set_actor(Actor val)
        {
            assert(val is Container);
            base._set_actor(val);
            /* TODO: add actor's children */
        }

        public ContainerModel(Actor act)
        {
            actor = act;
        }
    }
}

